package com.shansun.ws
{
	import com.shansun.dataobj.*;
	import com.shansun.event.AngryEvent;
	import com.shansun.util.BeanUtils;
	import com.shansun.util.JsonUtil;
	import com.shansun.xml.ToXmlBuilder;
	
	import flash.display.Sprite;
	
	import flex.lang.reflect.Method;
	
	import mx.controls.Alert;
	import mx.managers.CursorManager;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.soap.mxml.Operation;
	import mx.rpc.soap.mxml.WebService;
	import mx.utils.ObjectUtil;
	
	import navigators.TreeNav;
	
	import r1.deval.util.StringBuffer;

	public final class WebServiceHelper extends Sprite
	{
		private static var _classInfos:Array=new Array();

		private static var _remoteIP:String="";
		private static var _remotePort:Number=0;
		private static var _servCenter:String="ComTaobaoWlbJmxCommonBeanJwsProviders";

		private static var _servListWS:WebService=null;

		private static var _eventNames:Array=new Array();

		private static var _success:String='_SUCCESS';

		private static var _fault:String='_FAULT';

		private static var _servMapping:Object=new Object();

		public static function set RemoteIP(value:String):void
		{
			_remoteIP=value;
		}

		public static function get RemoteIP():String
		{
			return _remoteIP;
		}

		public static function set EventNames(value:Array):void
		{
			_eventNames=value;
		}

		public static function get EventNames():Array
		{
			return _eventNames;
		}

		public static function get ClassInfos():Array
		{
			return _classInfos;
		}

		public static function set ClassInfos(value:Array):void
		{
			_classInfos=value;
		}

		public static function get RemotePort():Number
		{
			return _remotePort;
		}

		public static function set RemotePort(value:Number):void
		{
			_remotePort=value;
		}

		public static function get ServCenter():String
		{
			return _servCenter;
		}

		public static function set ServCenter(value:String):void
		{
			_servCenter=value;
		}

		public static function get WsdlURL():String
		{
			if (_remotePort != 0 && _remoteIP != "")
			{
				return "http://" + _remoteIP + ":" + _remotePort + "/" + _servCenter + "?wsdl";
			}
			else
			{
				Alert.show("远程服务地址后端口未设置！", "初始化错误");
			}
			
			return null;
		}

		private static function getWsdlURL(className:String):String
		{
			if (_remotePort != 0 && _remoteIP != "")
			{
				return "http://" + _remoteIP + ":" + _remotePort + "/" + parseClassName(className) + "?wsdl";
			}
			else
			{
				Alert.show("远程服务地址后端口未设置！", "初始化错误");
			}
			
			return null;
		}
		
		private static function parseClassName(className:String):String {
			var servName:StringBuffer = new StringBuffer(className.charAt(0).toLocaleUpperCase());
			for(var i:int = 1; i < className.length; i++) {
				if('.' == className.charAt(i)) {
					i++;
					servName.append(className.charAt(i).toUpperCase());
				} else {
					servName.append(className.charAt(i));
				}
			}
			return servName.toString();
		}

		public function get ServListWS():WebService
		{
			if (_servListWS == null)
			{
				_servListWS=new WebService();
				_servListWS.loadWSDL(WsdlURL);
				_servListWS.useProxy=false;
				_servListWS.showBusyCursor=true;
				_servListWS.queryWebServices.resultFormat='object';
				_servListWS.queryWebServices.addEventListener(ResultEvent.RESULT, onGetServiceList);
				_servListWS.queryWebServices.addEventListener(FaultEvent.FAULT, onFault);
			}
			
			return _servListWS;
		}

		public function onGetServiceList(event:ResultEvent):void
		{ 
			deserializeJsonToClassInfo(event.result.toString());

			for each (var obj:ClassDesc in ClassInfos)
			{
				addService(obj.name, newWebService(obj.name, obj));
			}

			var xml:XML=ToXmlBuilder.toXmlTreeData(WebServiceHelper.ClassInfos);
			TreeNav.treeNavData=xml.children(); 
			
			CursorManager.removeBusyCursor();
		}

		public function newWebService(className:String, clazz:ClassDesc):WebService
		{
			var ws:WebService=new WebService();
			ws.useProxy=false;
			ws.showBusyCursor=true;
			ws.loadWSDL(getWsdlURL(className));

			var methods:Array=clazz.methods;
			for each (var meth:Object in methods)
			{
				var methodName:String=meth.name;
				ws[methodName].resultFormat='object';
				ws[methodName].addEventListener(ResultEvent.RESULT, onResultEvent);
				ws[methodName].addEventListener(FaultEvent.FAULT, onFaultEvent);
				EventNames[className + '_' + methodName]=className + '_' + methodName;
			}

			return ws;
		}

		public function onResultEvent(event:ResultEvent):void
		{
			var op:Operation=event.currentTarget as Operation;
			var path:String = getServiceNameByWebService(op.service as WebService) + '_' + op.name;
			var eventName:String=WebServiceHelper.EventNames[path] + _success;
			dispatchEvent(new AngryEvent(eventName, event));
		}

		public function onFaultEvent(event:FaultEvent):void
		{
			var op:Operation=event.currentTarget as Operation;
			var path:String = getServiceNameByWebService(op.service as WebService) + '_' + op.name;
			var eventName:String=WebServiceHelper.EventNames[path] + _fault;
			dispatchEvent(new AngryEvent(eventName, event));
		}

		public function onFault(event:FaultEvent):void
		{
			Alert.show(event.toString()); 
		}

		public static function addService(className:String, ws:WebService):void
		{
			_servMapping[className]=ws;
		}

		public static function removeService(className:String):void
		{
			delete _servMapping[className];
		}

		public static function getService(className:String):WebService
		{
			return _servMapping[className];
		}
		
		public static function set servMapping(value:Object):void
		{
			_servMapping = value;	
		}

		public static function get servMapping():Object
		{
			return _servMapping;	
		}
		
		public static function getServiceNameByWebService(ws:WebService):String
		{
			var claInfo:Object=ObjectUtil.getClassInfo(_servMapping);
			var props:Array=claInfo["properties"];
			for each (var q:QName in props)
			{
				var localName:String=q.localName;  
				if(ws == _servMapping[localName])
					return localName;
			}
			return null;
		}
		
		public static function getMethod(opName:String, servName:String):Operation
		{
			var ws:WebService=getService(servName);
			for each (var op:Operation in ws.operations)
			{
				if (opName == op.name)
				{
					return op;
				}
			}
			return null;
		}

		public function WebServiceHelper()
		{
			//throw new Error("不允许初始化该类！");
		}

		private static var _instance:WebServiceHelper;

		public static function get instance():WebServiceHelper
		{
			if (_instance == null)
			{
				_instance=new WebServiceHelper();
			}
			return _instance;
		}

		public static function deserializeJsonToClassInfo(jsonStr:String):Array
		{
			var obj:Object=JsonUtil.deserialize(jsonStr);
			for each(var clazz:Object in obj) { 
				var c:ClassDesc = new ClassDesc();
				c.name = clazz.name;
				for each(var meth:Object in clazz.methods) { 
					var m:MethodDesc = new MethodDesc();
					m.name = meth.name;
					for each(var param:Object in meth.params) { 
						var p:ParamDesc = new ParamDesc(); 
						p.type = param.type;
						p.enums = param.values;
						m.params.push(p);
					}
					c.methods.push(m);
				}
				ClassInfos.push(c);
			}
			return ClassInfos;
		}

		public static function getClassInfoByServiceName(serviceName:String):ClassDesc
		{
			for each (var obj:ClassDesc in ClassInfos)
			{
				if (obj.name == serviceName)
				{
					return obj;
				}
			}
			
			return null;
		}
		
		public static function getMethodInfo(serviceName:String, methodName:String):MethodDesc
		{
			var clzInfo:ClassDesc = getClassInfoByServiceName(serviceName);
			if(clzInfo == null) return null;
			for each (var mInfo:MethodDesc in clzInfo.methods)
			{
				if(mInfo == null) return null;
				if(methodName == mInfo.name)
				{
					return mInfo;
				}
			}
			return null;
		}
		
		public static function getServiceNameByClassName(className:String):String
		{
			return className; 
		}
	}
}